/**
 * 双端队列
 */
export class Deque<T> {

    private _count: number;
    private _lowestCount: number;
    private _items: any;

    public constructor() {
        this._count = this._lowestCount = 0;
        this._items = {};
    }

    /**
     * 前端添加
     * @param ele 
     */
    public addFront(ele: T) {
        if (this.isEmpty()) {
            this.addBack(ele);
        } else if (this._lowestCount > 0) {
            this._lowestCount--;
            this._items[this._lowestCount] = ele;
        } else {
            for (let i = this._count; i > 0; i--) {
                this._items[i] = this._items[i - 1];
            }
            this._count++;
            this._items[0] = ele;
        }
    }

    /**
     * 后端添加
     * @param ele 
     */
    public addBack(ele: T) {
        this._items[this._count] = ele;
        this._count++;
    }

    /**
     * 从前端移除第一个元素
     */
    public removeFront() {
        if (this.isEmpty()) {
            return undefined;
        }
        const result = this._items[this._lowestCount];
        delete this._items[this._lowestCount];
        this._lowestCount++;
        return result;
    }

    /**
     * 从后端移除一个元素
     */
    public removeBack() {
        if (this.isEmpty()) {
            return undefined;
        }
        this._count--;
        const result = this._items[this._count];
        delete this._items[this._count];
        return result;
    }

    /**
     * 从前端返回第一个元素(不对队列产生任何影响)
     */
    public peekFront() {
        if (this.isEmpty()) {
            return undefined;
        }
        return this._items[this._lowestCount];
    }

    /**
    * 从后端返回第一个元素(不对队列产生任何影响)
    */
    public peekBack() {
        if (this.isEmpty()) {
            return undefined;
        }
        return this._items[this._count - 1];
    }

    public isEmpty() {
        return this.length === 0;
    }

    public clear() {
        this._items = {};
        this._count = 0;
        this._lowestCount = 0;
    }

    public get length() {
        return this._count - this._lowestCount;
    }

    public toString() {
        if (this.isEmpty()) {
            return '';
        }
        let objString = `${this._items[this._lowestCount]}`;
        for (let i = this._lowestCount + 1; i < this._count; i++) {
            objString = `${objString},${this._items[i]}`;
        }
        return objString;
    }
}